package cn.iocoder.yudao.framework.pay.util;

import com.alibaba.fastjson.JSONObject;

import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.*;
import java.util.Base64;
import java.util.Map;
import java.util.TreeMap;

/**
 * 汇付专用 RSA 签名工具类
 * 支持：
 * 1. JSONObject 按键名 ASCII 升序排序
 * 2. SHA256WithRSA 签名
 * 3. SHA256WithRSA 验签
 */
public class HuifuRsaSignUtil {

    private static final String SIGN_ALGO = "SHA256WithRSA";
    private static final String KEY_ALGO = "RSA";
    // 服务商私钥，用于调用接口时进行签名
    public static final String DEMO_RSA_PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2dY7+eZ+BRgrIPFAZ+oL6wj+LHxiofGVgzAQdiVh6LB2XakPX/RBsI4t/wciES7Gjy3IdqYua1MbEPROeLdwGnQrZzVFY/J5Yc8FlJjd10pYaflb2g7cwAIvc1rZZXepONkGBf+u1Sh1c9eeKUNvxspPiCxbdjRnpHOk4KmZE1Z+M1D4uxTaE0OWqoloxmcYS49Yx0vXtDOwtue9uDTu14xKKtihqf40MsyQ82voHUYsF3KD1Bk5Kd4LGDF0dXsIy5nKg5gAkYAfoXssWO0eOGAv3w9NLJxNvQSPBdubYF37OjQWf6ImzgX70wwymLbULRIzyhiF1PdpnzD/Ooyp/AgMBAAECggEAT438dipTiMsgYmQhzOH0gB94E1HQr43lqgnqdXJwOHzJvj5gLGmz4mKxLVgx9LUIVFGdhR9qtmy16dRznFGEkQGiPIsQQAuNgyWdmlvKbL4QIqcZhcyyb+SdFwIradXQFqADedJr1JTnLqQte5p7++uQHUwWgS1HseOgMJQUGUiK9HW/elvYFJ3W7EHQZQ9xtyn4nNdrefqgMAmbUlkIeowlAoTsSpktfGsGTtz/xZ6am5D09Y0lId1XJNrpB4Z6LgE/bA3ba9LS7diTa4Wc5VddTgv9WaCmbj2qSmdm7fkqXvUR6Lhy+kPo4GdCvrwS0RrSUe7QRffj94h0SpiyQQKBgQDhAqVUqpO5rk/sqjaOdH+OJf+rEwbudv8zlwRr7uIQBgQYpRqh7f5oN3WCC9Eh3+7dPkdCj6eEMv73K9UZYaEJR5pNysLPC+ZciBg3TrjSMe8MnR4by9Ah4WmxrIBBU6lx4CIgz1ZvtPrFfuX5KxX0/qHTigNch9LUxkHbg4GNnwKBgQDPlqgbxApVWhxHavitZ7Cc+eAhRrMVs8LuSo92SrF71j7JUN9vcsnxZ1Zs3D+1Wh3BkXnJ4Uwqr62SprsfVqdNCC+dcC7TOjG9pWy9XZal5AKhOC4MqfmVIp7v7TmA8ZxkR4Auae8/7b9Otmk8h8xPvT7LCFYG2UuBVyRsYgV3IQKBgQDX8kMcE609KfbYyq8bXuFAWmWaGOOxHxFjwM7ki1n4SN3LjUEXIaLlADzNd2vZl+HWAbxAPEBoFs0uCKo29sSndEm52RvHu8L1EUQ0aF/mkze6IlxQDvYMXhqjA0v/5jwb5yC53mM1SDrYKiaqUNh8zZgfvjflqREFVdTEyNwgPwKBgF02lT4ChXFWCSS4j/mteczDFzVZ/chc88b0i/7eA1xME91qByqQLMXNVS2EqMbSNFJa9IkGNaFlSVd0rsmfq3gXmOnlGeGXXAaAZZeSkrbi75tdErB1ErE43o11xEB2PXd588DjqJ7YLvM1TYP0pnWX0L5ye86PfCwT6TMRwMqBAoGATwfRNnc8xrMilElicRkqu8PnDvXC08d4HTfsI0b1X43wyS4H7VSX63JJjnUPPqpMkZW3hlA1VBv+AnqK+wwAOa52WzxyfciAsOL1ukBceXuIHnvhunJhMMSvoH3UoQtJMY/b5/iFaiHDNl9cejW5rESLlDwZIvq7jb59BroEAu0=";

    // 汇付公钥，用于对汇付返回报文进行签名验证
    public static final String DEMO_RSA_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoAkxgifg0e0Agbsy9xIQXCowJFWQ/QTvpdK3YRxHSmEemFsQ69Y0pnldlII9yXocMgCKK5DRC4VkHBnAT0fI4sYGCARtaa1h75UYc1IKFGNQV86pTYsU6tAfPwTchpTjcDMQcB+iGf5AHpuzei6wiM4dEbN8VV/SK/IDNzWA9jM7qf5PO9yNDv03w9eTqA6Bcea7Kza4xvJ9T3jFSwTYogTk9jtHdC1GrS85GR1Jlhn/AaBzAuvYnw920TROGyLi+YRCaW7zs3p8CdGos04Vj/iuTBykc5YL2DL02ci3+dQ6SA/NkyATA+T+GY6pl8jiGiWER6URpGxEJTT5eQsHhwIDAQAB";

    /**
     * 将 JSONObject 按键名 ASCII 升序排序，
     * 并返回一个新的、键顺序已排好的 JSONObject。
     */
    public static String sortJsonObject(JSONObject input) {
        Map<String, Object> sorted = new TreeMap<>();
        for (Map.Entry<String, Object> e : input.entrySet()) {
            Object v = e.getValue();
            if (v != null && !"".equals(v.toString())) {
                sorted.put(e.getKey(), v);
            }
        }
        //  将排好序的 JSONObject 序列化为字符串，Fastjson 会按照 Map 顺序输出
        return new JSONObject(sorted).toJSONString();
    }

    /**
     * RSA 私钥签名：签名方式 SHA256WithRSA（汇付接口专用）
     *
     * @param data             待签名字符串
     * @param privateKeyBase64 私钥（Base64 编码，PKCS#8 格式）
     * @return Base64 签名结果
     * @throws GeneralSecurityException 解码或签名失败时抛出
     */
    public static String sign(String data, String privateKeyBase64)
            throws GeneralSecurityException {

        byte[] keyBytes = Base64.getDecoder().decode(privateKeyBase64);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        PrivateKey priKey = KeyFactory.getInstance(KEY_ALGO).generatePrivate(spec);

        Signature sig = Signature.getInstance(SIGN_ALGO);
        sig.initSign(priKey);
        sig.update(data.getBytes(StandardCharsets.UTF_8));
        byte[] signed = sig.sign();
        return Base64.getEncoder().encodeToString(signed);
    }

    /**
     * RSA 公钥验签：验签方式 SHA256WithRSA（汇付接口专用）
     *
     * @param data            原始字符串
     * @param publicKeyBase64 公钥（Base64 编码，X.509 格式）
     * @param signatureBase64 签名值（Base64 编码）
     * @return true 验签通过；false 验签失败
     * @throws GeneralSecurityException 解码或验签失败时抛出
     */
    public static boolean verify(String data,
                                 String publicKeyBase64,
                                 String signatureBase64)
            throws GeneralSecurityException {

        byte[] keyBytes = Base64.getDecoder().decode(publicKeyBase64);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        PublicKey pubKey = KeyFactory.getInstance(KEY_ALGO).generatePublic(spec);

        Signature sig = Signature.getInstance(SIGN_ALGO);
        sig.initVerify(pubKey);
        sig.update(data.getBytes(StandardCharsets.UTF_8));
        byte[] sigBytes = Base64.getDecoder().decode(signatureBase64);
        return sig.verify(sigBytes);
    }
}
